import {ISoundGroup} from "./ISoundGroup";
import {ISoundGroupHelper} from "./ISoundGroupHelper";
import {SoundAgent} from "./SoundAgent";
import {ISoundHelper} from "./ISoundHelper";
import {ISoundAgentHelper} from "./ISoundAgentHelper";
import {PlaySoundErrorCode} from "./PlaySoundErrorCode";
import {PlaySoundParams} from "./PlaySoundParams";
import {ISoundAgent} from "./ISoundAgent";

export class SoundGroup implements ISoundGroup {
    get Helper(): ISoundGroupHelper {
        return this._soundGroupHelper;
    }

    get Volume(): number {
        return this._volume;
    }

    set Volume(value: number) {
        this._volume = value;
        for (let i = 0; i < this._soundAgents.length; i++) {
            this._soundAgents[i].RefreshVolume();
        }
    }

    get Mute(): boolean {
        return this._mute;
    }

    set Mute(value: boolean) {
        this._mute = value;
        for (let i = 0; i < this._soundAgents.length; i++) {
            this._soundAgents[i].RefreshMute();
        }

    }

    get AvoidBeingReplacedBySamePriority(): boolean {
        return this._avoidBeingReplacedBySamePriority;
    }

    set AvoidBeingReplacedBySamePriority(value: boolean) {
        this._avoidBeingReplacedBySamePriority = value;
    }

    get SoundAgentCount(): number {
        return this._soundAgents.length;
    }

    get Name(): string {
        return this._name;
    }

    private readonly _name: string;
    private readonly _soundGroupHelper: ISoundGroupHelper;
    private readonly _soundAgents: Array<SoundAgent>;
    private _avoidBeingReplacedBySamePriority: boolean;
    private _mute: boolean;
    private _volume: number;


    constructor(name: string, soundGroupHelper: ISoundGroupHelper) {
        if (name == "" || name == undefined) {
            throw new Error("Sound group name is invalid.");
        }

        if (soundGroupHelper == null) {
            throw new Error("Sound group helper is invalid.");
        }

        this._name = name;
        this._soundGroupHelper = soundGroupHelper;
        this._soundAgents = [];
    }

    public AddSoundAgentHelper(soundHelper: ISoundHelper, soundAgentHelper: ISoundAgentHelper): void {
        this._soundAgents.push(new SoundAgent(this, soundHelper, soundAgentHelper));
    }

    public PlaySound(serialId: number, soundAsset, playSoundParams: PlaySoundParams, errorCode?: PlaySoundErrorCode): ISoundAgent {
        errorCode = null;
        let candidateAgent: SoundAgent = null;
        for (const soundAgent in this._soundAgents) {
            if (this._soundAgents[soundAgent].IsPlaying) {
                candidateAgent = this._soundAgents[soundAgent];
                break;
            }
            if (this._soundAgents[soundAgent].Priority < playSoundParams.priority) {
                if (candidateAgent == null || this._soundAgents[soundAgent].Priority < candidateAgent.Priority) {
                    candidateAgent = this._soundAgents[soundAgent];
                }
            } else if (!this._avoidBeingReplacedBySamePriority && this._soundAgents[soundAgent].Priority == playSoundParams.priority) {
                if (candidateAgent == null || this._soundAgents[soundAgent].setSoundAssetTime < candidateAgent.setSoundAssetTime) {
                    candidateAgent = this._soundAgents[soundAgent];
                }
            }

        }

        if (candidateAgent == null) {
            errorCode = PlaySoundErrorCode.IgnoredDueToLowPriority;
            return null;
        }

        if (!candidateAgent.SetSoundAsset(soundAsset)) {
            errorCode = PlaySoundErrorCode.SetSoundAssetFailure;
            return null;
        }

        candidateAgent.SerialId = serialId;
        candidateAgent.Time = playSoundParams.time;
        candidateAgent.MuteInSoundGroup = playSoundParams.muteInSoundGroup;
        candidateAgent.Loop = playSoundParams.loop;
        candidateAgent.Priority = playSoundParams.priority;
        candidateAgent.VolumeInSoundGroup = playSoundParams.volumeInSoundGroup;
        candidateAgent.Pitch = playSoundParams.pitch;
        candidateAgent.PanStereo = playSoundParams.panStereo;
        candidateAgent.SpatialBlend = playSoundParams.spatialBlend;
        candidateAgent.MaxDistance = playSoundParams.maxDistance;
        candidateAgent.DopplerLevel = playSoundParams.dopplerLevel;
        candidateAgent.Play(playSoundParams.fadeInSeconds);
        return candidateAgent;
    }


    public StopSound(serialId: number, fadeOutSeconds: number): boolean {
        for (let soundAgent in this._soundAgents) {
            if (this._soundAgents[soundAgent].SerialId != serialId) {
                continue;
            }

            this._soundAgents[soundAgent].Stop(fadeOutSeconds);
            return true;
        }

        return false;
    }


    public PauseSound(serialId: number, fadeOutSeconds: number): boolean {
        for (let soundAgent in this._soundAgents) {
            if (this._soundAgents[soundAgent].SerialId != serialId) {
                continue;
            }

            this._soundAgents[soundAgent].Pause(fadeOutSeconds);
            return true;
        }
        return false;
    }

    public ResumeSound(serialId: number, fadeInSeconds: number): boolean {
        for (let soundAgent in this._soundAgents) {
            if (this._soundAgents[soundAgent].SerialId != serialId) {
                continue;
            }

            this._soundAgents[soundAgent].Resume(fadeInSeconds);
            return true;
        }
        return false;
    }


    StopAllLoadedSounds(): void;
    StopAllLoadedSounds(fadeOutSeconds: number): void;
    StopAllLoadedSounds(fadeOutSeconds?: number): void {
        for (let i = 0; i < this._soundAgents.length; i++) {
            let isPlaying: boolean = this._soundAgents[i].IsPlaying;
            if (isPlaying) {
                this._soundAgents[i].Stop(fadeOutSeconds)
            }
        }
    }

}